from sqlmodel import Session, Field, select, and_, or_
from dependencies import engine, SessionDep
from typing import Union, List, Optional
import models
import utility
from common import exception
import datetime

"""查询用户信息

Keyword arguments:
username -- 用户名
Return: 
common_user -- 用户信息
"""


def get_current_user(session: Session, username: str | None = None, type: int = 1):
    try:
        # 查询条件
        conditions = [
            models.User.username == username if username else True,
            models.User.type == type,
        ]

        # 构建查询语句
        statement = select(models.User).where(*conditions)

        # 执行查询
        common_user = session.exec(statement=statement).one_or_none()
        
        return common_user
    except Exception as e:
        session.rollback()
        raise e


"""查询全部用户（医生/患者）

Keyword arguments:
skip: int = 0,
limit: int = 20,
username: str | None = None,
phone: str | None = None,
type: int | None = None,
user_id: int = Depends(manager),
Return: return_description
"""


def get_user(
    skip: int = 0,
    limit: int = 20,
    username: str | None = None,
    phone: str | None = None,
    type: int | None = None,
    user_id: int = None,
    session: Optional[SessionDep] = Session(engine),
):
    # 查询条件列表
    conditions = [
        models.User.username.like(f"%{username}%") if username else True,
        models.User.phone.like(f"%{phone}%") if phone else True,
        models.User.type == type if type is not None else True,
    ]

    # 查询语句
    statement = (
        select(models.User)
        .filter(and_(*conditions))
        .order_by(models.User.updatetime)
        .offset(skip)
        .limit(limit)
    )

    # 执行查询
    items = session.exec(statement).all()

    # 初始化用户列表
    users = []

    # 遍历用户列表
    for item in items:
        # 获取关联的患者
        patients = item.patients
        # 获取关联的医生
        doctor = item.doctor
        # 转换为字典
        item = dict(item)

        # 将创建人和更新人ID转化成姓名
        if item["create_id"]:
            item["creator"] = session.get(
                models.SystemUser, item["create_id"]).name
        if item["update_id"]:
            item["updater"] = session.get(
                models.SystemUser, item["update_id"]).name
        # 添加到用户列表
        if patients:
            item["patients"] = [dict(patient) for patient in patients]
        if doctor:
            item["doctor"] = dict(doctor)

        # 添加到用户列表
        users.append(item)

    return users


"""新增医生

Keyword arguments:
doctor_create -- 新增医生信息
    username -- 用户名
    docotr -- 医生信息
        name -- 医生姓名
        job_num -- 工号
        phone -- 手机号
        title -- 职称
        department -- 科室
        org_id -- 所属机构
        is_active -- 状态
Return: 
create_user -- 新增用户（医生）信息
"""


def create_doctor(
    doctor_create: models.UserDoctorCreate,
    user: models.SystemUser = None,
    session: Optional[SessionDep] = Session(engine),
):
    # 校验用户名不能为空
    if not doctor_create.username:
        raise exception.create_http_exception(400, "用户名不能为空")
    # 校验用户名是否重复
    elif session.exec(
        select(models.User).where(
            models.User.username == doctor_create.username)
    ).first():
        raise exception.create_http_exception(400, "用户名已存在")
    # 校验手机号不能为空
    elif not doctor_create.phone.strip() or not doctor_create.doctor.phone.strip():
        raise exception.create_http_exception(400, "手机号不能为空")
    # 校验手机号格式不正确
    elif not utility.security.is_valid_phone_number(
        doctor_create.phone
    ) or not utility.security.is_valid_phone_number(doctor_create.doctor.phone):
        raise exception.create_http_exception(400, "手机号格式不正确")
    # 校验手机号是否重复
    elif (
        session.exec(
            select(models.User).where(models.User.phone == doctor_create.phone)
        ).first()
        or session.exec(
            select(models.Doctor).where(
                models.Doctor.phone == doctor_create.doctor.phone
            )
        ).first()
    ):
        raise exception.create_http_exception(400, "手机号已存在")
    # 校验工号是否重复
    elif session.exec(
        select(models.Doctor).where(
            models.Doctor.job_num == doctor_create.doctor.job_num
        )
    ).first():
        raise exception.create_http_exception(400, "工号已存在")

    # 创建用户
    create_user = models.User(
        username=doctor_create.username,
        phone=doctor_create.phone,
        password=utility.security.get_hashed_password(),
        type=2,
        create_id=user.id if user else None,
        update_id=user.id if user else None,
        createtime=datetime.datetime.now(),
        updatetime=datetime.datetime.now(),
    )
    # 创建医生
    create_doctor = models.Doctor(
        job_num=doctor_create.doctor.job_num,
        name=doctor_create.doctor.name,
        phone=doctor_create.doctor.phone,
        title=doctor_create.doctor.title,
        department=doctor_create.doctor.department,
        org_id=doctor_create.doctor.org_id,
        is_active=doctor_create.doctor.is_active,
        create_id=user.id if user else None,
        update_id=user.id if user else None,
        createtime=datetime.datetime.now(),
        updatetime=datetime.datetime.now(),
        user=create_user,
    )
    # 添加到数据库
    session.add(create_user)
    session.add(create_doctor)
    session.commit()
    return create_user


"""编辑医生
Keyword arguments:
id -- 医生id
doctor_create -- 新增医生信息
    username -- 用户名
    docotr -- 医生信息
        name -- 医生姓名
        job_num -- 工号
        phone -- 手机号
        title -- 职称
        department -- 科室
        org_id -- 所属机构
        is_active -- 状态
Return: 
update_user -- 更新用户（医生）信息
"""


def update_doctor(
    id: int,
    doctor_update: models.UserDoctorUpdate,
    user: models.SystemUser = None,
    session: Optional[SessionDep] = Session(engine),
):
    # 查询医生详情ID
    doctor_id = session.get(models.User, id).doctor.id

    # 校验用户ID是否存在
    if not session.exec(select(models.User).where(models.User.id == id)).first():
        raise exception.create_http_exception(400, "用户ID不存在")
    # 校验用户名是否重复
    elif session.exec(
        select(models.User).where(
            models.User.username == doctor_update.username,
            models.User.id != id,  # 排除当前用户
        )
    ).first():
        raise exception.create_http_exception(400, "用户名已存在")
    # 校验用户名不能为空
    elif not doctor_update.username:
        raise exception.create_http_exception(400, "用户名不能为空")
    # 校验手机号不能为空
    elif not doctor_update.phone.strip() or not doctor_update.doctor.phone.strip():
        raise exception.create_http_exception(400, "手机号不能为空")
    # 校验手机号格式不正确
    elif not utility.security.is_valid_phone_number(
        doctor_update.phone
    ) or not utility.security.is_valid_phone_number(doctor_update.doctor.phone):
        raise exception.create_http_exception(400, "手机号格式不正确")
    # 校验手机号是否重复
    elif (
        session.exec(
            select(models.User).where(
                models.User.phone == doctor_update.phone,
                models.User.id != id,  # 排除当前用户
            )
        ).first()
        or session.exec(
            select(models.Doctor).where(
                models.Doctor.phone == doctor_update.doctor.phone,
                models.Doctor.id != doctor_id,  # 排除当前用户
            )
        ).first()
    ):
        raise exception.create_http_exception(400, "手机号已存在")
    # 校验工号是否重复
    elif session.exec(
        select(models.Doctor).where(
            models.Doctor.job_num == doctor_update.doctor.job_num,
            models.Doctor.id != doctor_id,  # 排除当前用户
        )
    ).first():
        raise exception.create_http_exception(400, "工号已存在")

    # 查询医生用户
    update_user = session.get(models.User, id)
    # 编辑用户
    update_user.username = doctor_update.username
    update_user.phone = doctor_update.doctor.phone
    update_user.update_id = user.id
    update_user.updatetime = datetime.datetime.now()

    session.add(update_user)
    session.commit()

    # 查询医生
    update_doctor = session.exec(
        select(models.Doctor).where(models.Doctor.user_id == id)
    ).first()

    # 编辑医生
    update_doctor.job_num = doctor_update.doctor.job_num
    update_doctor.name = doctor_update.doctor.name
    update_doctor.phone = doctor_update.doctor.phone
    update_doctor.title = doctor_update.doctor.title
    update_doctor.department = doctor_update.doctor.department
    update_doctor.org_id = doctor_update.doctor.org_id
    update_doctor.is_active = doctor_update.doctor.is_active

    session.merge(update_doctor)
    session.flush()

    session.commit()
    return update_user


"""患者注册

Keyword arguments:
patient_create -- 患者注册信息
    username -- 用户名
    phone -- 手机号
    password -- 密码
Return: 
create_patient -- 新增患者
"""


def create_patient(
    patient_create: models.UserPatientsCreate,
    session: Optional[SessionDep] = Session(engine),
):
    # 校验用户名不能为空
    if not patient_create.username:
        raise exception.create_http_exception(400, "用户名不能为空")
    # 校验用户名是否重复
    elif session.exec(
        select(models.User).where(
            models.User.username == patient_create.username)
    ).first():
        raise exception.create_http_exception(400, "用户名已存在")
    # 校验手机号不能为空
    elif not patient_create.phone.strip():
        raise exception.create_http_exception(400, "手机号不能为空")
    # 校验手机号格式不正确
    elif not utility.security.is_valid_phone_number(patient_create.phone):
        raise exception.create_http_exception(400, "手机号格式不正确")
    # 校验手机号是否重复
    elif session.exec(
        select(models.User).where(models.User.phone == patient_create.phone)
    ).first():
        raise exception.create_http_exception(400, "手机号已存在")
    # 校验密码不能为空
    elif not patient_create.password:
        raise exception.create_http_exception(400, "密码不能为空")
    # 校验密码格式不正确
    elif not utility.security.validate_password(patient_create.password)[0]:
        raise exception.create_http_exception(
            400, utility.security.validate_password(patient_create.password)[1]
        )

    # 创建患者
    create_patient = models.User(
        username=patient_create.username,
        phone=patient_create.phone,
        password=utility.security.get_hashed_password(patient_create.password),
        type=1,
        createtime=datetime.datetime.now(),
        updatetime=datetime.datetime.now(),
    )

    session.add(create_patient)
    session.commit()
    session.refresh(create_patient)
    return create_patient


"""患者手机号变更

Keyword arguments:
id -- 用户id
old_phone -- 旧手机号
new_phone -- 新手机号
Return: 
modify_phone -- 修改手机号
"""


def modify_phone(
    id: int,
    old_phone: str,
    new_phone: str,
    user: models.SystemUser = None,
    session: Optional[SessionDep] = Session(engine),
):
    # 校验id是否存在
    modify_phone = session.get(models.User, id)
    if not modify_phone:
        raise exception.create_http_exception(400, "用户ID不存在")
    # 校验旧手机号是否一致
    elif modify_phone.phone != old_phone:
        raise exception.create_http_exception(400, "旧手机号不正确")
    # 校验新手机和旧手机不能一致
    elif old_phone == new_phone:
        raise exception.create_http_exception(400, "新手机号不能与旧手机号一致")
    # 校验新手机号是否已存在
    elif session.exec(
        select(models.User).where(
            models.User.phone == new_phone,
            models.User.id != id,)
    ).first():
        raise exception.create_http_exception(400, "手机号已存在")

    # 修改手机号
    modify_phone.phone = new_phone
    modify_phone.updatetime = datetime.datetime.now()
    session.add(modify_phone)
    session.commit()
    session.refresh(modify_phone)
    return modify_phone


"""修改密码（医生/患者）

Keyword arguments:
id -- 用户id
old_password -- 旧密码
new_password -- 新密码
Return: 
modify_password -- 修改/重置密码
"""


def modify_password(
    id: int,
    old_password: str,
    new_password: str,
    user: models.SystemUser = None,
    session: Optional[SessionDep] = Session(engine),
):
    # 获取用户信息
    modify_password = session.get(models.User, id)
    # 查询用户ID是否存在
    if not modify_password:
        raise exception.create_http_exception(400, "用户ID不存在")
    # 校验旧密码是否正确
    elif not utility.security.verify_password(old_password, user.password):
        raise exception.create_http_exception(400, "旧密码不正确")
    # 校验新密码是否合法
    elif new_password and not utility.security.validate_password(new_password)[0]:
        raise exception.create_http_exception(
            400, utility.security.validate_password(new_password)[1]
        )

    # 修改密码
    modify_password.password = utility.security.get_hashed_password(
        new_password)
    modify_password.update_id = user.id
    modify_password.updatetime = datetime.datetime.now()
    session.add(modify_password)
    session.commit()
    return modify_password


"""重置密码（医生/患者）

Keyword arguments:
id -- 用户（医生/患者）id
Return: 
reset_password -- 重置密码
"""


def reset_password(
    id: int,
    user: models.SystemUser = None,
    session: Optional[SessionDep] = Session(engine),
):
    # 查询用户ID是否存在
    if not session.exec(select(models.User).where(models.User.id == id)).first():
        raise exception.create_http_exception(400, "用户ID不存在")

    # 获取用户信息
    reset_password = session.get(models.User, id)
    # 重置密码
    reset_password.password = utility.security.get_hashed_password()
    reset_password.update_id = user.id
    reset_password.updatetime = datetime.datetime.now()
    session.add(reset_password)
    session.commit()
    return reset_password


"""删除用户（医生/患者）

Keyword arguments:
id -- 用户id
Return: delete_user
"""


def delete_user(
    id: int,
    session: Optional[SessionDep] = Session(engine),
):
    # 查询用户ID是否存在
    if not session.exec(select(models.User).where(models.User.id == id)).first():
        raise exception.create_http_exception(400, "用户ID不存在")

    # 查询用户
    user = session.get(models.User, id)

    # 删除用户
    session.delete(user)
    session.commit()
    return delete_user


"""添加就诊人（患者）

Keyword arguments:
add_patient -- 添加就诊人信息
    name -- 姓名
    sex -- 性别
    birthday  -- 生日
    id_card -- 身份证号
    outpatient_num  -- 门诊号
    inpatient_num   -- 住院号
    medical_record_num   -- 病历号
    phone   -- 手机号
user -- 用户信息（患者/医生）
Return: 
add_patient -- 添加就诊人
"""

def add_patient(
    add_patient: models.PatientCreate,
    user: models.User = None,
    session: Optional[SessionDep] = Session(engine),
):
    # 校验身份证号是否合法
    if not utility.security.validate_id_card(add_patient.id_card):
        raise exception.create_http_exception(400, "身份证号不合法")
    # 根据证件号校验用户是否存在
    elif session.exec(select(models.Patient).where(models.Patient.id_card == add_patient.id_card)).first():
        raise exception.create_http_exception(400, "用户已存在")
    # 校验门诊号是否存在
    elif session.exec(select(models.Patient).where(models.Patient.outpatient_num == add_patient.outpatient_num)).first() and add_patient.outpatient_num:
        raise exception.create_http_exception(400, "门诊号已存在")
    # 校验住院号是否存在
    elif session.exec(select(models.Patient).where(models.Patient.inpatient_num == add_patient.inpatient_num)).first() and add_patient.inpatient_num:
        raise exception.create_http_exception(400, "住院号已存在")
    # 校验病历号是否存在
    elif session.exec(select(models.Patient).where(models.Patient.medical_record_num == add_patient.medical_record_num)).first() and add_patient.medical_record_num:
        raise exception.create_http_exception(400, "病历号已存在")
    # 校验手机号是否合法
    if not utility.security.is_valid_phone_number(add_patient.phone):
        raise exception.create_http_exception(400, "手机号格式不正确")
    # 校验手机号已存在
    elif session.exec(select(models.Patient).where(models.Patient.phone == add_patient.phone)).first():
        raise exception.create_http_exception(400, "手机号已存在")
    # 添加就诊人
    add_new_patient = models.Patient(
        name=add_patient.name,
        sex=add_patient.sex,
        birthday=add_patient.birthday,
        id_card=add_patient.id_card,
        outpatient_num=add_patient.outpatient_num if add_patient.outpatient_num else None,
        inpatient_num=add_patient.inpatient_num if add_patient.inpatient_num else None,
        medical_record_num=add_patient.medical_record_num if add_patient.medical_record_num else None,
        phone=add_patient.phone,
        create_id=user.id,
        createtime=datetime.datetime.now(),
        update_id=user.id,
        updatetime=datetime.datetime.now(),
    )
    session.add(add_new_patient)  # 提交会话以获取 add_new_patient 的 ID
    session.flush()  # 刷新会话以获取 add_new_patient 的 ID
    add_user_patient = models.UserPatientLink(
        user_id=user.id, patient_id=add_new_patient.id)
    # 添加就诊人关系表
    session.add(add_user_patient)
    session.commit()
    session.refresh(add_new_patient)
    session.refresh(add_user_patient)
    return add_patient


"""关联就诊人（患者）

Keyword arguments:
id_card -- 身份证号
phone -- 手机号
user -- 用户信息（患者/医生）
Return: 
add_user_patient -- 关联关系
"""


def relate_patient(
    id_card: str,
    phone: str,
    user: models.User = None,
    session: Optional[SessionDep] = Session(engine),
):
    # 身份证号相同，手机号不同，则提示：为保护患者隐私，系统检测到您输入的手机号与预留信息不符
    if session.exec(select(models.Patient).where(
        models.Patient.id_card == id_card,
        models.Patient.phone != phone,
    )).first():
        raise exception.create_http_exception(
            400, "为保护患者隐私，系统检测到您输入的手机号与预留信息不符")
    # 身份证号相同，手机号相同且关联表中有关联关系，则提示：当前就诊人已关联
    elif session.exec(select(models.Patient).where(
        models.Patient.id_card == id_card,
        models.Patient.phone == phone,
    )).first() and session.exec(select(models.UserPatientLink).where(
        models.UserPatientLink.user_id == user.id,
        models.UserPatientLink.patient_id == session.exec(select(models.Patient).where(
    models.Patient.id_card == id_card,
        models.Patient.phone == phone,
    )).first().id,
    )).first():
        raise exception.create_http_exception(400, "当前就诊人已关联")
    # 没有找到身份证和手机号一致的患者，则提示：未找到该患者，请确认身份证号和手机号是否正确
    elif not session.exec(select(models.Patient).where(
        models.Patient.id_card == id_card,
        models.Patient.phone == phone,
    )).first():
        raise exception.create_http_exception(400, "未找到该患者，请确认身份证号和手机号是否正确")
    
    
    # 关联患者
    add_user_patient = models.UserPatientLink(
        user_id=user.id,
        patient_id=session.exec(select(models.Patient).where(
            models.Patient.id_card == id_card,
            models.Patient.phone == phone,
        )).first().id,
    )
    session.add(add_user_patient)
    session.commit()
    session.refresh(add_user_patient)
    return add_user_patient